package com.hex.ds.hdtp.core.app.sdm.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.hex.ds.hdtp.core.app.common.page.PageData;
import com.hex.ds.hdtp.core.app.common.page.converter.IPageAndPageDtoConverter;
import com.hex.ds.hdtp.core.app.common.page.dto.PageDto;
import com.hex.ds.hdtp.core.app.common.util.JaveShellUtil;
import com.hex.ds.hdtp.core.app.script.common.service.impl.ScriptConvertFileFilter;
import com.hex.ds.hdtp.core.app.sdm.converter.ISdmConvertTaskConverter;
import com.hex.ds.hdtp.core.app.sdm.dto.request.SdmConvertTaskRequestDto;
import com.hex.ds.hdtp.core.app.sdm.dto.response.SdmConvertTaskResponseDto;
import com.hex.ds.hdtp.core.app.sdm.enums.ConvertResultEnum;
import com.hex.ds.hdtp.core.app.sdm.service.ISdmConvertTaskService;
import com.hex.ds.hdtp.core.inf.common.page.Page;
import com.hex.ds.hdtp.core.inf.sdm.po.SdmConvertTaskPo;
import com.hex.ds.hdtp.core.inf.sdm.repository.ISdmConvertTaskRepository;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.List;

@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class SdmConvertTaskService implements ISdmConvertTaskService {

    @Value("${script.convert.relativePath}")
    private String relativePath;
    @Value("${sdm.remoteHost}")
    private String remoteHost;
    @Value("${sdm.username}")
    private String userName;
    @Value("${sdm.password}")
    private String password;
    @Value("${sdm.remotePath}")
    private String remotePath;
    @Value("${sdm.remotePort}")
    private int remotePort;
    @Value("${sdm.pyCommand}")
    private String command;
    private final ISdmConvertTaskRepository sdmConvertTaskRepository;
    private final ScriptConvertFileFilter scriptConvertFileFilter;
    private final ISdmConvertTaskConverter converter;
    private final JaveShellUtil javaShellUtil;
    private final IPageAndPageDtoConverter pageAndPageDtoConverter;


    /**
     * @Method upload <br>
     * @Param
     * @Param multipartFileList <br>
     * @Return java.util.List<java.io.File> <br>
     * @Description 上传文件<br>
     * @Author jian.qiao<br>
     * @Date 2023/11/1 19:56 <br>
     * @Version V1.0<br>
     */
    @Override
    public List<File> upload(List<MultipartFile> multipartFileList) {
        String sourceFilePath = getTmpFilePath("source-file");
        try {
            for (MultipartFile multipartFile : multipartFileList) {
                File uploadFile = new File(sourceFilePath + File.separator + multipartFile.getOriginalFilename());
                FileUtil.mkdir(uploadFile);
                multipartFile.transferTo(uploadFile);
            }
        } catch (Exception e) {
            log.error("文件上传失败:{}", e.getMessage(), e);
            throw new RuntimeException("文件上传失败！");
        }
        return FileUtil.loopFiles(sourceFilePath, scriptConvertFileFilter);
    }

    /**
     * @Method createTask <br>
     * @Param
     * @Param sdmConvertTaskRequestDto <br>
     * @Return java.lang.String <br>
     * @Description 创建任务<br>
     * @Author jian.qiao<br>
     * @Date 2023/11/1 19:56 <br>
     * @Version V1.0<br>
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public String createTask(SdmConvertTaskRequestDto sdmConvertTaskRequestDto) {
        //添加任务
        SdmConvertTaskPo sdmConvertTaskPo = addScriptConvertTask(sdmConvertTaskRequestDto);
        addScriptConvertFile(sdmConvertTaskPo,sdmConvertTaskRequestDto);
        //调用python
        Session session = createSession();
        String result = callPython(sdmConvertTaskPo,session);
        updateResult(sdmConvertTaskPo,result,session);
        return sdmConvertTaskPo.getPkId();
    }

    private void addScriptConvertFile(SdmConvertTaskPo sdmConvertTaskPo , SdmConvertTaskRequestDto sdmConvertTaskRequestDto) {
        File sourceFile = new File(sdmConvertTaskPo.getSourceFilePath());
        String filePath = CollUtil.getFirst(sdmConvertTaskRequestDto.getFileList());
        File uploadFile = new File(filePath);
        FileUtil.copyFilesFromDir(uploadFile, sourceFile, true);
    }

    /**
     * @Method queryListByPage <br>
     * @Param
     * @Param sdmConvertTaskRequestDto
     * @Param pageDto <br>
     * @Return com.hex.ds.hdtp.core.app.common.page.PageData <br>
     * @Description 分页查询<br>
     * @Author jian.qiao<br>
     * @Date 2023/11/2 10:57 <br>
     * @Version V1.0<br>
     */
    @Override
    public PageData queryListByPage(SdmConvertTaskRequestDto sdmConvertTaskRequestDto, PageDto pageDto) {
        final Page<SdmConvertTaskPo> pageResult = sdmConvertTaskRepository.queryListByPage(
                converter.toSdmConvertTaskPo(sdmConvertTaskRequestDto), pageAndPageDtoConverter.toPage(pageDto));
        List<SdmConvertTaskResponseDto> responseDtos = converter.toScriptConvertTaskResponseDtoList(pageResult.getData());
        return new PageData(responseDtos, pageResult.getTotal());
    }

    /**
     * @Method downloadFile <br>
     * @Param
     * @Param fileType
     * @Param pkId <br>
     * @Return java.lang.String <br>
     * @Description 下载文件<br>
     * @Author jian.qiao<br>
     * @Date 2023/11/2 10:57 <br>
     * @Version V1.0<br>
     */
    @Override
    public String downloadFile(String fileType, String pkId) {
        SdmConvertTaskPo sdmConvertTaskPo = sdmConvertTaskRepository.queryById(pkId);
        // 获取下载文件路径、源文件路径、转换文件路径
        String downloadFileRelativePath = getTmpFilePath("download-file");
        String sourceFilSavePath = "";
        String downFilePath = "";
        if (StrUtil.equalsAnyIgnoreCase("sourceFile", fileType)) {
            sourceFilSavePath = downloadFileRelativePath + File.separator + "sourceFile";
            downFilePath = sdmConvertTaskPo.getSourceFilePath();
        } else if (StrUtil.equalsAnyIgnoreCase("convertFile", fileType)) {
            sourceFilSavePath = downloadFileRelativePath + File.separator + "convertFile";
            downFilePath = sdmConvertTaskPo.getConvertFilePath();
        }
        // 将文件复制到下载目录下
        FileUtil.copyContent(new File(downFilePath), new File(sourceFilSavePath), true);
        //zip压缩下载文件
        ZipUtil.zip(downloadFileRelativePath);
        return downloadFileRelativePath + ".zip";
    }

    /**
     * @Method updateResult <br>
     * @Param
     * @Param sdmConvertTaskPo
     * @Param result
     * @Param session <br>
     * @Return void <br>
     * @Description 更新结果<br>
     * @Author jian.qiao<br>
     * @Date 2023/11/1 19:56 <br>
     * @Version V1.0<br>
     */
    public void updateResult(SdmConvertTaskPo sdmConvertTaskPo,String result,Session session){
        sdmConvertTaskPo.setStatus(ConvertResultEnum.SUCCESS.getName());
        String[] results = StrUtil.split(result,",");
        if (results.length != 3){
            sdmConvertTaskPo.setStatus(ConvertResultEnum.FAIL.getName());
        }
        sdmConvertTaskPo.setJobName(results[0]);
        sdmConvertTaskPo.setConvertFileName(FileUtil.getName(results[1]));
        sdmConvertTaskRepository.modifyById(sdmConvertTaskPo);
        try {
            //将远端文件拉到本地
            javaShellUtil.pullFileFromConnect(session,results[1],sdmConvertTaskPo.getConvertFilePath());
            session.disconnect();
        } catch (JSchException e) {
            throw new RuntimeException(e);
        } catch (SftpException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @Method callPython <br>
     * @Param
     * @Param sdmConvertTaskPo
     * @Param session <br>
     * @Return java.lang.String <br>
     * @Description 调用python<br>
     * @Author jian.qiao<br>
     * @Date 2023/11/2 10:57 <br>
     * @Version V1.0<br>
     */
    public String callPython(SdmConvertTaskPo sdmConvertTaskPo,Session session){
        //将文件上传服务器指定目录
        try {
            String remoteFilePath = remotePath.concat(StrUtil.toString(DateUtil.currentSeconds()));
            // 将平台上传指定服务器目录
            javaShellUtil.putFileToConnect(session, sdmConvertTaskPo.getSourceFilePath().concat(File.separator).concat(sdmConvertTaskPo.getSourceFileName()), remoteFilePath);
            //调用python
            String pyCommand = StrUtil.format(command + " {}", remoteFilePath);
            String result = javaShellUtil.executeCommandReturn(pyCommand,session);
            log.info("调用python脚本返回结果：{}",result);
            return result;
        } catch (JSchException e) {
            throw new RuntimeException(e);
        } catch (SftpException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @Method addScriptConvertTask <br>
     * @Param
     * @Param sdmConvertTaskRequestDto <br>
     * @Return com.hex.ds.hdtp.core.inf.sdm.po.SdmConvertTaskPo <br>
     * @Description 添加转换任务<br>
     * @Author jian.qiao<br>
     * @Date 2023/11/2 10:58 <br>
     * @Version V1.0<br>
     */
    public SdmConvertTaskPo addScriptConvertTask(SdmConvertTaskRequestDto sdmConvertTaskRequestDto){
        SdmConvertTaskPo sdmConvertTaskPo = converter.toSdmConvertTaskPo(sdmConvertTaskRequestDto);
        sdmConvertTaskPo.setSourceFileName(FileUtil.getName(CollUtil.getFirst(sdmConvertTaskRequestDto.getFileList())));
//        sdmConvertTaskPo.setSourceFilePath(CollUtil.getFirst(sdmConvertTaskRequestDto.getFileList()));
        sdmConvertTaskRepository.add(sdmConvertTaskPo);
        sdmConvertTaskPo.setSourceFilePath(getFileRelativePath(sdmConvertTaskPo.getPkId(), "source-file"));
        sdmConvertTaskPo.setConvertFilePath(getFileRelativePath(sdmConvertTaskPo.getPkId(), "converter-file"));
        sdmConvertTaskRepository.modifyById(sdmConvertTaskPo);
        return sdmConvertTaskPo;
    }

    public Session createSession(){
        try {
            Session session = javaShellUtil.getConnectSession(userName,remoteHost,password,remotePort);
            return session;
        } catch (JSchException e) {
            throw new RuntimeException(e);
        }
    }

    /*
     * @Method: getTmpFilePath <br>
     * @Param: [fileType] <br>
     * @Return: java.lang.String <br>
     * @Description：获取临时路径<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/14 10:46 <br>
     * @Version： V2.0.2<br>
     */
    private String getTmpFilePath(String fileType) {
        String filePath = StrUtil.format("{}/tmp/{}/{}/{}", relativePath, DateUtil.today(), fileType, System.currentTimeMillis());
        FileUtil.mkdir(filePath);
        return filePath;
    }

    /*
     * @Method: getFileRelativePath <br>
     * @Param: [taskId, fileType] <br>
     * @Return: java.lang.String <br>
     * @Description：获取脚本源文件和转换文件路径<br>
     * @Author： wz.li<br>
     * @Date： 2023/8/11 18:33 <br>
     * @Version： V2.0.2<br>
     */
    private String getFileRelativePath(String taskId, String fileType) {
        String filePath = StrUtil.format("{}/{}/{}/{}", relativePath, DateUtil.today(), taskId, fileType);
        FileUtil.mkdir(filePath);
        return filePath;
    }
}
